package com.free.fs.controller;

import cn.hutool.core.lang.UUID;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.text.DecimalFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 一个有意思的按钮游戏
 */
@Controller
@RequiredArgsConstructor
public class ButtonController {

    /**
     * 各用户存档
     */
    private static final HashMap<String, ButtonGame> _SaveGame = new HashMap<>();

    /**
     * 存档过期时间
     */
    private static final long _SaveCleanTime = 3 * 60 * 60 * 1000;

    /**
     * 用户唯一标识
     */
    private static final String _CookieKey = "buttonGame";

    /**
     * 金额格式化
     */
    private static final DecimalFormat _DF = new DecimalFormat(" #,###0.00");

    /**
     * 登录
     */
    @GetMapping("/" + _CookieKey)
    @ResponseBody
    public String buttonGame(Integer money, HttpServletRequest request, HttpServletResponse response) {
        // 没输入资金，提示开始
        if (money == null) {
            // 申请一个新CookieKey
            response.addCookie(new Cookie(_CookieKey, UUID.fastUUID().toString()));
            return "<head><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"></head><div align=\"center\"><h2>这是一个按钮游戏</h2><p />每次按下可以让你的游戏金币<b>翻9倍</b><p />或者降为原来的<b>十分之一</b><p /><h1></h1>网页链接后<b>输入你的初始游戏金币</b>，然后按回车开始游戏<p />例如：https://www.treks.cloud/buttonGame?money=1000 <a href=\"https://www.treks.cloud/buttonGame?money=1000\">直接从1000金币开始吧!</a><p /><hr> <font color=\"#a1a1a1\" size=\"1\">严正声明：此网站仅供娱乐学习使用。本网站初衷是简单的模拟金币走向趋势，用于研究随着按钮按下次数与最终所得金币的利害关系，同时警戒任何人应该对概率事件保持戒心。本网站内所使用的随机数均为伪随机数，不具备模拟现实中的概率事件的功能。本网站不对产生的任何随机结果负责。请勿将本网站用于任何与赌博相关的事件，本网站坚守严厉打击赌博内容，对犯罪分子绝不留情，鼓励举报赌博犯罪相关事件。<p/>相关文章：<a href=\"https://www.spp.gov.cn/flfg/gfwj/201208/t20120830_2438.shtml\">《最高人民法院、最高人民检察院、公安部关于办理网络赌博犯罪案件适用法律若干问题的意见》</a>、<a href=\"https://baike.baidu.com/item/%E8%B5%8C%E5%8D%9A%E7%BD%AA/5224831\">《赌博罪》</a>、<a href=\"https://cyberpolice.mps.gov.cn/#/\">《网络违法犯罪举报网站》</a></font></div>";
        }

        // 获取CookieKey
        Cookie[] cookies = request.getCookies();
        String key;
        if (cookies != null && cookies.length > 0 && Arrays.stream(cookies).anyMatch(i -> _CookieKey.equals(i.getName()))) {
            key = Arrays.stream(cookies).filter(i -> _CookieKey.equals(i.getName())).collect(Collectors.toList()).get(0).getValue();
        } else {
            // 获取不到，创建一个CookieKey
            key = UUID.fastUUID().toString();
            response.addCookie(new Cookie(_CookieKey, key));
        }

        // 根据CookieKey获取存档
        ButtonGame game = _SaveGame.get(key);
        if (game == null) {
            // 获取不到，创建一个存档
            game = new ButtonGame(money);
        }

        // 游戏逻辑
        {
            // 随机生成一个 [1,100] 的数
            int v = (int) (Math.random() * 100) + 1;

            // 记录一次按下
            game.totalCount++;

            // 如果v大于等于1、小于等于50
            if (v >= 1 && v <= 50) {
                // 资产翻9倍
                game.currentMoney = game.currentMoney * 9;
                // 记录历史
                game.history.add("第" + game.totalCount + "次按下按钮，金币翻番，拥有金币" + formatMoney(game.currentMoney));
                // 记录次数
                game.sucCount++;
                // 记录最大值
                if (game.currentMoney > game.maxMoney) {
                    game.maxMoney = game.currentMoney;
                    game.maxIndex = game.totalCount;
                }
            }

            // 如果v大于等于51、小于等于100
            if (v >= 51 && v <= 100) {
                // 资产变为0.1倍
                game.currentMoney = game.currentMoney * 0.1;
                // 输出记录
                game.history.add("第" + game.totalCount + "次按下按钮，金币缩降，拥有金币" + formatMoney(game.currentMoney));
                // 记录次数
                game.fldCount++;
                // 记录最小值
                if (game.currentMoney < game.minMoney) {
                    game.minMoney = game.currentMoney;
                    game.minIndex = game.totalCount;
                }
            }
        }

        // 记录存档
        _SaveGame.put(key, game);

        // 清除过期存档
        saveClean();

        // 结论
        String res0 = "<h3>当前金币为" + formatMoney(game.currentMoney) + "</h3>";
        String res1 = "你的初始金币为" + formatMoney(game.startMoney);
        String res2 = "你共按下" + game.totalCount + "次按钮，<b>" + game.sucCount + "次金币翻番</b>，" + game.fldCount + "次金币缩降";
        String res3 = "其中第" + game.maxIndex + "次按钮按下后，金币<b>最高</b>，达到了<b>" + formatMoney(game.maxMoney) + "</b>";
        String res4 = "其中第" + game.minIndex + "次按钮按下后，金币<b>最低</b>，达到了<b>" + formatMoney(game.minMoney) + "</b>";
        String res5 = "<p><a href=\"javascript:location.reload()\">再来</a>   &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  <a href=\"https://www.treks.cloud/buttonGame\">废了，重开吧</a></p>";

        return "<head><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"></head><div align=\"center\">" + res0 + "<p />" + res1 + "<p />" + res2 + "<p />" + res3 + "<p />" + res4 +  "<p />" + res5 + "<p /><p />" + "<hr><h1></h1><h3>历史记录</h3><p />" + String.join("<p />", game.getHistory()) + "</div>";
    }

    /**
     * 游戏存档实体类
     */
    private static class ButtonGame {

        /**
         * 当前资金
         */
        private double currentMoney;

        /**
         * 启动资金
         */
        private int startMoney;

        /**
         * 翻倍次数
         */
        private int sucCount;

        /**
         * 缩水次数
         */
        private int fldCount;

        /**
         * 总次数
         */
        private int totalCount;

        /**
         * 最大资金
         */
        private double maxMoney;

        /**
         * 最大资金次
         */
        private int maxIndex;

        /**
         * 最小资金
         */
        private double minMoney;

        /**
         * 最小资次
         */
        private int minIndex;

        /**
         * 游戏开始时间
         */
        private Date lastTime;

        /**
         * 游戏记录
         */
        private final List<String> history;

        public ButtonGame(int startMoney) {
            this.startMoney = startMoney;
            this.currentMoney = startMoney;
            this.sucCount = 0;
            this.fldCount = 0;
            this.totalCount = 0;
            this.maxMoney = startMoney;
            this.maxIndex = 0;
            this.minMoney = startMoney;
            this.minIndex = 0;
            this.lastTime = new Date();
            this.history = new ArrayList<>();
        }

        /**
         * 获取一个倒序的history
         */
        public List<String> getHistory() {
            List<String> temp = new ArrayList<>(history);
            Collections.reverse(temp);
            return temp;
        }

    }

    private static String formatMoney(double a) {
        return _DF.format(a);
    }

    // 清除过期存档
    private static synchronized void saveClean() {
        List<String> delKeys = new ArrayList<>();
        for (String key : _SaveGame.keySet()) {
            if (System.currentTimeMillis() - _SaveGame.get(key).lastTime.getTime() > _SaveCleanTime){
                delKeys.add(key);
            }
        }
        for (String key : delKeys) {
            _SaveGame.remove(key);
        }
    }
}
